package fts.ftscontrol;

import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

import fts.ftsmonitoring.ftsTaggers.IAutoTagger;
import fts.ftsdata.IDataFactory;
import fts.ftsdata.domain.ITag;
import fts.ftsdata.domain.ITaggedFile;
import fts.ftsdata.domain.IWatchFolder;
import fts.ftsdata.domain.IWatchWildcard;
import fts.ftsdata.services.IConfigurationService;
import fts.ftsdata.services.ILookupService;
import fts.ftsdata.services.ITaggingService;
import fts.ftsmonitoring.initializer.FTSInitializer;
import fts.ftsmonitoring.initializer.IInitializerObserver;
import fts.ftsmonitoring.FileMonitoringRoot;
import fts.ftsmonitoring.IFileMonitoringService;
import fts.ftsmonitoring.IFileObserver;
import fts.ftsmonitoring.InitializationStatus;

public class Facade
{
	private IFileMonitoringService monitoringService;
	private Thread monitoringThread = null;
	
	private ILookupService lookupService;
	private ITaggingService taggingService;
	private IConfigurationService configurationService;

	private Collection<IWatchFolder> watchFolders;
	private FileChangeObserver fcObserver;
	
	public Facade(IDataFactory dataFactory, IFileMonitoringService monitoringService)
	{
		System.out.println(Thread.currentThread().getStackTrace()[1]);

		this.monitoringService = monitoringService;
		
		this.lookupService = dataFactory.getLookupService();
		this.taggingService = dataFactory.getTaggingService();
		this.configurationService = dataFactory.getConfigurationService();
		try
		{
			this.watchFolders = this.configurationService.getAllWatchFolders();
		}
		catch (Exception e)
		{
			this.watchFolders = new ArrayList<IWatchFolder>();
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		fcObserver = new FileChangeObserver(this, taggingService, lookupService);
		this.monitoringService.registerFileObserver(fcObserver);
	}
	
	public Collection<? extends ITaggedFile> getFilesByTagExpression(String expression, int pageNum, int pageSize) throws Exception
	{
		System.out.println(Thread.currentThread().getStackTrace()[1]);

		return lookupService.getFilesByTagExpression(expression, pageNum, pageSize);
	}
	
	public Collection<? extends ITag> getAllTags() throws Exception
	{
		System.out.println(Thread.currentThread().getStackTrace()[1]);

		return lookupService.getAllTags();
	}
	
	public ITaggedFile getFileByName(String str) throws Exception
	{
		System.out.println(Thread.currentThread().getStackTrace()[1]);

		return lookupService.getFileByName(str);
	}
	
	public void addTagToFile(String fileName, String tag) throws Exception
	{
		System.out.println(Thread.currentThread().getStackTrace()[1]);

		ITaggedFile file = taggingService.createTaggedFile(fileName);

		ITag tagObj = taggingService.createTag(tag);
		
		file.addManualTag(tagObj);

		taggingService.saveTaggedFile(file);
	}
	
	public void addFile(String fileName) throws Exception
	{
		System.out.println(Thread.currentThread().getStackTrace()[1]);

		if(getFileByName(fileName) == null)
		{
			taggingService.saveTaggedFile(taggingService.createTaggedFile(fileName));
		}
	}
	
	public void deleteFile(String fileName) throws Exception
	{
		System.out.println(Thread.currentThread().getStackTrace()[1]);

		ITaggedFile file = getFileByName(fileName);
		
		if(file != null)
		{
			taggingService.deleteTaggedFile(file);
		}
	}
	
	public void addFileObserver(IFileObserver observer)
	{
		System.out.println(Thread.currentThread().getStackTrace()[1]);

		monitoringService.registerFileObserver(observer);
	}
	
	public void removeFileObserver(IFileObserver observer)
	{
		System.out.println(Thread.currentThread().getStackTrace()[1]);

		monitoringService.unregisterFileObserver(observer);
	}
	
	public void addInitializerObserver(IInitializerObserver observer)
	{
		System.out.println(Thread.currentThread().getStackTrace()[1]);

		FTSInitializer.getInstance().registerInitializerObserver(observer);
	}
	
	public void removeInitializerObserver(IInitializerObserver observer)
	{
		System.out.println(Thread.currentThread().getStackTrace()[1]);

		FTSInitializer.getInstance().unregisterInitializerObserver(observer);
	}
	

	public void addAutoTagger(IAutoTagger tagger)
	{
		System.out.println(Thread.currentThread().getStackTrace()[1]);

		fcObserver.addTagger(tagger);
		FTSInitializer.getInstance().addTagger(tagger);
	}
	
	public void removeAutoTagger(IAutoTagger tagger)
	{
		System.out.println(Thread.currentThread().getStackTrace()[1]);

		fcObserver.removeTagger(tagger);
		FTSInitializer.getInstance().removeTagger(tagger);
	}
	
	public int getInitializationProgress()
	{
		return FTSInitializer.getInstance().getProgress();
	}
	
	public InitializationStatus getInitializationStatus()
	{
		return FTSInitializer.getInstance().getStatus();
	}
	
	public Iterator<IWatchFolder> getWatchFoldersIterator()
	{
		return this.watchFolders.iterator();
	}
	
	public void addWatchFolder(String path) throws Exception
	{
		if(path == null || !new File(path).exists() || !new File(path).isDirectory())
		{
			return;
		}

		configurationService.saveWatchFolder(configurationService.createWatchFolder(path));
		this.watchFolders = this.configurationService.getAllWatchFolders();
	}
	
	public void deleteWatchFolder(String path) throws Exception
	{
		System.out.println(Thread.currentThread().getStackTrace()[1]);

		IWatchFolder folder = configurationService.getWatchFolder(path);
		if(folder != null)
		{
			configurationService.deleteWatchFolder(folder);
			this.watchFolders = this.configurationService.getAllWatchFolders();
		}
	}
	
	public void addWatchFolderWildcard(String path, String wildcard) throws Exception
	{
		IWatchFolder folder = configurationService.getWatchFolder(path);
		if(folder != null)
		{
			folder.addWildcard(configurationService.createWatchWildcard(wildcard, folder));
			configurationService.saveWatchFolder(folder);
			this.watchFolders = this.configurationService.getAllWatchFolders();
		}
	}
	
	public void deleteWatchFolderWildcard(String path, String wildcard) throws Exception
	{
		IWatchFolder folder = configurationService.getWatchFolder(path);
		if(folder != null)
		{
			folder.removeWildcard(configurationService.createWatchWildcard(wildcard, null));
			configurationService.saveWatchFolder(folder);
			this.watchFolders = this.configurationService.getAllWatchFolders();
		}
	}
	
	public void startFileMonitoring()
	{
		if(monitoringThread != null && monitoringThread.isAlive())
		{
			return;
		}
		System.out.println(Thread.currentThread().getStackTrace()[1]);

		Collection<FileMonitoringRoot> dirsAndPatterns = getRootsAndPatterns();
		
		monitoringThread = new Thread(new MonitoringServiceThread(monitoringService, dirsAndPatterns));
		monitoringThread.start();
	}

	private Collection<FileMonitoringRoot> getRootsAndPatterns()
	{
		Collection<FileMonitoringRoot> dirsAndPatterns  = new ArrayList<FileMonitoringRoot>();
		
		Iterator<? extends IWatchFolder> iterF = getWatchFoldersIterator();
		while(iterF.hasNext())
		{
			IWatchFolder fold = iterF.next();
			Iterator<? extends IWatchWildcard> iterW = fold.getWildcardsIterator();
			ArrayList<String> patts = new ArrayList<String>();
			while(iterW.hasNext())
			{
				patts.add(iterW.next().getWildcard());
			}
			String[] pattArr = new String[patts.size()];
			pattArr = patts.size() > 0 ? patts.toArray(pattArr) : new String[]{"*.*"};
			FileMonitoringRoot root = new FileMonitoringRoot(fold.getPath(), patts.toArray(pattArr));
			dirsAndPatterns.add(root);
		}
		return dirsAndPatterns;
	}
	

	public void stopFileMonitoring()
	{
		System.out.println(Thread.currentThread().getStackTrace()[1]);

		if(monitoringThread != null && monitoringThread.isAlive())
		{
			monitoringService.stopMonitoring();
			try
			{
				monitoringThread.join();
			}
			catch (InterruptedException e)
			{
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

	public void startInitializerThread()
	{
		Collection<FileMonitoringRoot> dirsAndPatterns = getRootsAndPatterns();
		
		FTSInitializer.getInstance().runAsync(dirsAndPatterns, this.taggingService);
	}
	
	public void stopInitializerThread()
	{
		FTSInitializer.getInstance().Stop();
	}
}
